#include <kvs/glut/Application>
#include <kvs/glut/Screen>
#include <kvs/StructuredVolumeObject>
#include <kvs/StructuredVolumeImporter>
#include <kvs/PolygonObject>
#include <kvs/Isosurface>
#include <kvs/TransferFunction>
#include <kvs/StochasticPolygonRenderer>
#include <kvs/StochasticRenderingCompositor>
#include <kvs/Shader>
#include <kvs/Light>
#include <kvs/RotationMatrix33>
#include <kvs/KeyPressEventListener>


class KeyPress : public kvs::KeyPressEventListener
{
    void update( kvs::KeyEvent* event )
    {
        screen()->redraw();
        switch ( event->key() )
        {
        case kvs::Key::s:
            ((kvs::glut::Screen*)(screen()))->scene()->camera()->snapshot().write("snapshot.bmp");
            break;
        default:
            break;
        }
    }
};

kvs::PolygonObject* ExtractIsosurfaces( const std::string& filename )
{
    kvs::StructuredVolumeObject* volume = new kvs::StructuredVolumeImporter( filename );
    volume->updateMinMaxValues();

    const double i = ( volume->maxValue() + volume->minValue() ) * 0.5;
    const kvs::PolygonObject::NormalType n = kvs::PolygonObject::VertexNormal;
    const bool d = false;
    const kvs::TransferFunction t( 256 );
    kvs::PolygonObject* object = new kvs::Isosurface( volume, i, n, d, t );
    delete volume;
    return object;
}

int main( int argc, char** argv )
{
    kvs::glut::Application app( argc, argv );
    kvs::glut::Screen screen( &app );
    screen.setBackgroundColor( kvs::RGBColor::White() );
    screen.setSize( 800, 800 );
    screen.show();

    kvs::PolygonObject* object1 = ExtractIsosurfaces( argv[1] );
    object1->setColor( kvs::RGBColor::Yellow() );
    object1->setOpacity( 255 );
    kvs::StochasticPolygonRenderer* renderer1 = new kvs::StochasticPolygonRenderer();
    screen.registerObject( object1, renderer1 );

    kvs::PolygonObject* object2 = ExtractIsosurfaces( argv[2] );
    object2->setColor( kvs::RGBColor( 255, 100, 100 ) );
    object2->setOpacity( atoi( argv[3] ) );
    kvs::StochasticPolygonRenderer* renderer2 = new kvs::StochasticPolygonRenderer();
    renderer2->setShader( kvs::Shader::Phong() );
    screen.registerObject( object2, renderer2 );

    KeyPress key;
    screen.addEvent( &key );

//    kvs::Xform x = kvs::Xform::Scaling( 2.0 )
    kvs::Xform x = kvs::Xform::Scaling( 1.0 )
        * kvs::Xform::Rotation( kvs::YRotationMatrix33<float>( 55 ) )
        * kvs::Xform::Rotation( kvs::XRotationMatrix33<float>( 50 ) );
    object1->multiplyXform( x );
    object2->multiplyXform( x );

    screen.scene()->camera()->setPosition( kvs::Vector3f( 0, 0, 6 ) );

    kvs::StochasticRenderingCompositor compositor( screen.scene() );
    compositor.setRepetitionLevel( 50 );
    compositor.enableLODControl();
    compositor.enableRefinement();
    screen.setEvent( &compositor );

    kvs::Light::SetModelTwoSide( true );

    return app.run();
}
